from database.park_location_record_table import ParkLocationRecordTable
from manager.lock_manager import LockManager
from model.park_spider import ParkSpider
from model.park_platform import ParkPlatform
from model.car_number import CarNumber
from model.result import Result
from model.error import BannedAccountError, ParkSpiderError, ParkSpiderErrorCode

import dateutil.parser as dateutil

import re
import time
import json
import common.verify as verify

import common.http as http
import threading
from common.logger import logger
import spider_config
import random


class SuParkSpider(ParkSpider):
    def platform(self) -> ParkPlatform:
        return ParkPlatform(spider_config.su_park_id)

    def buildHeaders(self):
        account = self.getAccount()
        headers = {
            "Host" : "cloud.keytop.cn",
            "Accept" : "application/json, text/plain, */*",
            #"accessToken" : account["token"],
            "User-Agent" : "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1 Edg/119.0.0.0",
            "Content-Type" : "application/json",
            "Origin" : "https://cloud.keytop.cn",
            "Referer" : "https://cloud.keytop.cn/stcfront/Parking/Query",
            "Accept-Encoding" : "gzip, deflate, br",
            "Accept-Language" : "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
            "Cookie" : f"pp_user_hash={account['userhash']}; pp_user_id={account['userid']};",
        }
        return headers

    def blockPuzzle(self):
        headers = self.buildHeaders()

        url = "https://cloud.keytop.cn/captcha-middle-api/blockPuzzle/front/getToken"

        data = {"captchaType": "blockPuzzle"}

        rsp = http.post(
            url,
            headers=headers,
            data=json.dumps(data),
            proxies=self.getProxy(),
            timeout=self.getTimeout(),
        )

        if rsp.status_code != 200:
            return False, f"status_code:{rsp.status_code}, url:{url}"

        j = rsp.json()

        if j["repCode"] != "0000":
            return False, j.dumps()

        # 随机0-1秒
        time.sleep(random.random() + 1)

        token = j["repData"]["token"]

        bg = j["repData"]["originalImageBase64"]
        jg = j["repData"]["jigsawImageBase64"]

        px = verify.blockPuzzle(bg, jg)
        py = 5

        headers["token"] = token
        headers["px"] = str(px)
        headers["py"] = str(py)

        url = "https://cloud.keytop.cn/service/front/userCenter/unsealed"

        rsp = http.post(
            url, headers=headers, proxies=self.getProxy(), timeout=self.getTimeout()
        )

        if rsp.status_code != 200:
            return False, f"status_code:{rsp.status_code}, url:{url}"

        rspJson = rsp.json()

        info = f"message:{rspJson['message']}, bk:{bg}, jg:{jg}, px:{px}, py:{py}"

        return rspJson["code"] == 2000, info

    def getAccountId(self):
        account = self.getAccount()
        if 'userid' in account:
            return account['userid']
        else:
            return account

    def query(self, carNumber: CarNumber) -> Result:
        account = self.getAccount()

        if not account:
            raise ParkSpiderError(ParkSpiderErrorCode.SuAccountEmpty)

        with LockManager.instance().get(self.platform().id, self.getAccountId()):
            pass

        result = Result()
        result.platform = self.platform()
        result.car_number = carNumber

        url = "https://cloud.keytop.cn/service/front/parking/wxa/city"

        headers = self.buildHeaders()

        # {"lpn":"鄂A11111","cityId":"294","plateColor":"BLUE","isCardNo":false}
        data = {
            "lpn": f"{carNumber.province}{carNumber.city}{carNumber.number}",
            "cityId": "109",
            "plateColor": "BLUE",
            "isCardNo": False,
        }

        rsp = http.post(
            url,
            headers=headers,
            data=json.dumps(data),
            proxies=self.getProxy(),
            timeout=self.getTimeout(),
        )

        rspJson = rsp.json()

        if rspJson["code"] == 3004:
            raise BannedAccountError(self.getAccountId())

        sub_code = rspJson["subCode"]

        if sub_code == 998:
            logger.warning(f"{self.getAccountId()} 违规账号")
            raise BannedAccountError(self.getAccountId())
        elif sub_code == 999:
            if LockManager.instance().locked(self.platform().id, self.getAccountId()):
                with LockManager.instance().get(self.platform().id, self.getAccountId()):
                    pass
                return self.query(carNumber)

            with LockManager.instance().get(self.platform().id, self.getAccountId()):
                result.error_code = rsp.status_code
                result.message = rsp.text
                result.message = f"{self.getAccountId()} 人机验证中"
                logger.debug(result.message)
                repeat = 0

                while True:
                    success, info = self.blockPuzzle()
                    if success:
                        logger.debug(f"{self.getAccountId()} 滑块验证成功,继续查询")
                        break
                    else:
                        if repeat > 10:
                            result.message = f"{self.getAccountId()} 滑块验证失败"
                            logger.error(result.message)
                            return result
                        else:
                            repeat += 1
                            result.message = f"{self.getAccountId()} 验证失败,重试{repeat}次({info})"
                            logger.debug(result.message)

            return self.query(carNumber)

        logger.debug(f"速停车测试:{str(carNumber)}: {rspJson}")

        if rsp.status_code != 200:
            result.error_code = rsp.status_code
            result.message = rsp.text
            return result
        
        result.error_code = rspJson["code"]
        result.success = rspJson["code"] == 2000
        result.message = rspJson["message"] if "message" in rspJson else ""

        if not result.success:
            return result

        data["encodeLotId"] = rspJson["data"]["encodeLotId"]
        data["token"] = rspJson["data"]["token"]

        url = "https://cloud.keytop.cn/service/front/paymentCard/compose"

        rsp = http.post(
            url,
            headers=headers,
            data=json.dumps(data),
            proxies=self.getProxy(),
            timeout=self.getTimeout(),
        )

        if rsp.status_code != 200:
            result.error_code = rsp.status_code
            result.message = rsp.text
            return result

        rspJson = rsp.json()

        result.error_code = rspJson["code"]
        result.success = rspJson["code"] == 2000
        result.message = rspJson["message"] if "message" in rspJson else ""

        if not result.success:
            return result

        result.enter_time = dateutil.parse(
            rspJson["data"]["orderConfirmInfo"]["comeTime"]
        )
        result.price = rspJson["data"]["orderConfirmInfo"]["cashFee"] / 100
        result.park_name = rspJson["data"]["orderConfirmInfo"]["lotName"]

        if "correction_url" in rspJson["data"]:
            correction_url = rspJson["data"]["correction_url"]
            lotid = re.search(r"lotId=(\d+)", correction_url).group(1)
        else:
            lotid = rspJson["data"]["orderConfirmInfo"]["lotId"]

        # 获取停车场名称接口有时会返回502，重试一般都能好
        for i in range(5):
            url = f"https://pb.keytop.cn/privacyprotection/isShowLpn?plateNum=0&lotId={lotid}&source=10"
            rsp = http.get(url, proxies=self.getProxy(), timeout=self.getTimeout())
            if rsp.status_code == 200:
                result.park_name = rsp.json()["data"]["lotName"]
                break
            else:
                logger.warning(f"速停车获取停车场名称{rsp.status_code},重试{i+1}次")
                
        with ParkLocationRecordTable(spider_config.su_park_id) as db:
            record = db.query_by_name(result.park_name)
            if record:
                result.park_name = record

        # 获取入场图片接口
        # https://ss-service.keytop.cn/cn.keytop.stc.cp.misc.front.payment.ParkingImg/1.0/?_=1670309671158&lotId=NJ6dbYa1ETT-C884oomyNQ%3D%3D&imgName=20221205002456605_192.168.171.131_011492.jpg

        return result
